#include <Arduino.h>
#include "rm67162.h"
#include <TFT_eSPI.h> //https://github.com/Bodmer/TFT_eSPI
#include "true_color.h"
#include "app.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include "pins_config.h"
/* USB CDC on boot must be set to enable */

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);
#define WIDTH 536
#define HEIGHT 240

uint8_t brightness = 0xA0;
// 1. Replace with your network credentials
const char *ssid = "";
const char *password = "";

// 2. Replace with your OpenAI API key
String apiKey = "sk-f42611ee893c499490535fcb9e9b8b16";

// Send request to OpenAI API
String inputText = "你好，通义千问！";
String apiUrl = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation";

String answer;
String getGPTAnswer(String inputText)
{
  HTTPClient http;
  http.begin(apiUrl);
  http.addHeader("Content-Type", "application/json");
  http.addHeader("Authorization", apiKey);
  String payload = "{\"model\":\"qwen-turbo\",\"input\":{\"messages\":[{\"role\": \"system\",\"content\": \"你是鹏鹏的生活助手机器人，要求下面的回答严格控制在256字符以内。\"},{\"role\": \"user\",\"content\": \"" + inputText + "\"}]}}";
  int httpResponseCode = http.POST(payload);
  if (httpResponseCode == 200)
  {
    String response = http.getString();
    http.end();
    Serial.println(response);

    // Parse JSON response
    DynamicJsonDocument jsonDoc(1024);
    deserializeJson(jsonDoc, response);
    String outputText = jsonDoc["output"]["text"];
    return outputText;
    // Serial.println(outputText);
  }
  else
  {
    http.end();
    Serial.printf("Error %i \n", httpResponseCode);
    return "<error>";
  }
}

/* for baidu stt*/
#include "BaiduRest.h"
// #include "M5Atom.h"
#include <driver/i2s.h>

#define CONFIG_I2S_BCK_PIN 47
#define CONFIG_I2S_LRCK_PIN 8
#define CONFIG_I2S_DATA_PIN 46
#define CONFIG_I2S_DATA_IN_PIN 0

#define SPEAK_I2S_NUMBER I2S_NUM_0

#define MODE_MIC 0
#define MODE_SPK 1

bool InitI2SSpeakOrMic(int mode)
{
  esp_err_t err = ESP_OK;

  i2s_driver_uninstall(SPEAK_I2S_NUMBER);
  i2s_config_t i2s_config = {
      .mode = (i2s_mode_t)(I2S_MODE_MASTER),
      .sample_rate = 16000,
      .bits_per_sample =
          I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
      .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 1, 0)
      .communication_format =
          I2S_COMM_FORMAT_STAND_I2S, // Set the format of the communication.
#else                                // 设置通讯格式
      .communication_format = I2S_COMM_FORMAT_I2S,
#endif
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
      .dma_buf_count = 6,
      .dma_buf_len = 60,
  };
  if (mode == MODE_MIC)
  {
    i2s_config.mode =
        (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
  }
  else
  {
    i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
    i2s_config.use_apll = false;
    i2s_config.tx_desc_auto_clear = true;
  }

  Serial.println("Init i2s_driver_install");

  err += i2s_driver_install(SPEAK_I2S_NUMBER, &i2s_config, 0, NULL);
  i2s_pin_config_t tx_pin_config;

#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0))
  tx_pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
#endif
  tx_pin_config.bck_io_num = CONFIG_I2S_BCK_PIN;      // 47
  tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN;      // 8
  tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN;   // 46
  tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN; // 0

  Serial.println("Init i2s_set_pin");
  err += i2s_set_pin(SPEAK_I2S_NUMBER, &tx_pin_config);
  Serial.println("Init i2s_set_clk");
  err += i2s_set_clk(SPEAK_I2S_NUMBER, 16000, I2S_BITS_PER_SAMPLE_16BIT,
                     I2S_CHANNEL_MONO);

  return true;
}

BaiduRest rest;
uint8_t microphonedata0[1024 * 80];
size_t byte_read = 0;
int16_t *buffptr;
uint32_t data_offset = 0;
size_t bytes_written;
#define DATA_SIZE 1024
String SpakeStr;
bool Spakeflag = false;

/* for keyController*/
unsigned long gamepad_last_handled_time = 0;

void handleGamepadChange()
{
  if (millis() - gamepad_last_handled_time < 500)
  {
    return;
  }
  bool handled = false;
  if (keypad_states[GAMEPAD_UP])
  {
    handled = true;
  }
  // else if (keypad_states[GAMEPAD_DOWN])
  // {
  //   handled = true;
  // }
  else if (keypad_states[GAMEPAD_LEFT])
  {
    handled = true;
  }
  else if (keypad_states[GAMEPAD_RIGHT])
  {
    handled = true;
  }
  // else if (keypad_states[GAMEPAD_PRESSED])
  // {

  //   handled = true;
  // }
  if (handled)
  {
    gamepad_last_handled_time = millis();
  }
}

void setup()
{
  // Initialize Serial
  Serial.begin(115200);

  /*initialization for llm*/

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());

  /* initializing Microphone*/
  Serial.println("Init Mic");
  InitI2SSpeakOrMic(MODE_SPK);
  delay(100);
  rest.settoken("5002919f3af02f3d1752963b1dcde0c6");
  // rest.settoken("f0f5bd4bf6b490cbd7fce518cd58de96");

  answer = getGPTAnswer(inputText);
  Serial.println("Answer: " + answer);
  Serial.println("Enter a prompt:");

  /* initialization for display*/
  pinMode(0, INPUT);
  rm67162_init();
  lcd_setRotation(1);
  spr.createSprite(WIDTH, HEIGHT);
  spr.setSwapBytes(1);
  // delay(5000);
  lcd_setBrightness(brightness);
  Serial.println("setup() done");
  spr.setCursor(10, spr.height() / 2, 2);
  spr.setTextColor(TFT_MAGENTA);
  spr.setTextSize(3);
  spr.print("Setup done!");
  // spr.pushSprite(0, 0);
  // spr.pushImage(0, 0, WIDTH, HEIGHT, (uint16_t *)gImage_true_color);
  lcd_PushColors(0, 0, WIDTH, HEIGHT, (uint16_t *)spr.getPointer());
  delay(2000);
  Wire.begin(43, 44);
  setup_aw9523();
  // setup_keypad();
  // setup_spm1423();
  // setup_amoled();
}

/* things for tts*/

String textToConvert = "你好，这是要转换为语音的文本。";
uint8_t pcmBuffer[81920]; // 确保这个足够大来存储PCM数据
size_t pcmLength = 0;

int spd = 5; // 示例值
int pit = 5; // 示例值
int volo = 5; // 示例值
int per = 0; // 示例值，发音人参数

void loop()
{
  // do nothing
  loop_aw9523();
  if (Serial.available())
  {
    inputText = Serial.readStringUntil('\n');
    // inputText.trim();
    Serial.println("\n Input:" + inputText);

    answer = getGPTAnswer(inputText);
    Serial.println("Answer: " + answer);
    Serial.println("Enter a prompt:");
  }
  // delay(2);

#if 1
  if (keypad_states[GAMEPAD_UP])
  {
    data_offset = 0;
    Spakeflag = false;

    InitI2SSpeakOrMic(MODE_MIC);
    spr.fillSprite(0);
    spr.setCursor(10, spr.height() / 2, 2);
    spr.print("Start Recording!");
    lcd_PushColors(0, 0, WIDTH, HEIGHT, (uint16_t *)spr.getPointer());
    while (1)
    {
      i2s_read(SPEAK_I2S_NUMBER, (char *)(microphonedata0 + data_offset),
               DATA_SIZE, &byte_read, (100 / portTICK_RATE_MS));
      data_offset += 1024;
      // M5.update();
      if (data_offset >= 81919)
        break;
      // delay(60);
    }
    Serial.println("end");

    if (rest.Pcm2String(microphonedata0, data_offset, DEV_PID_MANDARIN,
                        &SpakeStr) != -1)
    {
      Serial.println(SpakeStr);

      // inputText = Serial.readStringUntil('\n');
      // inputText.trim();
      // Serial.println("\n Input:" + inputText);

      answer = getGPTAnswer(SpakeStr);
      Serial.println("Answer: " + answer);

      int result = rest.String2Pcm( answer, spd, pit, volo, per, pcmBuffer, &pcmLength);

      if (result == 0)
      {
        Serial.println("转换成功！");
        // 处理pcmBuffer中的PCM数据，例如播放语音或保存到文件
      }
      else
      {
        Serial.println("转换失败...");
      }
      Serial.println("Enter a prompt:");
      spr.fillSprite(0);
      spr.setCursor(10, spr.height() / 2, 2);
      spr.print("stt finished!");
      lcd_PushColors(0, 0, WIDTH, HEIGHT, (uint16_t *)spr.getPointer());
      Spakeflag = true;
      // M5.dis.drawpix(0, CRGB(128, 0, 128));
    }
    else
    {
      // M5.dis.drawpix(0, CRGB(0, 128, 0));
      spr.fillSprite(0);
      spr.setCursor(10, spr.height() / 2, 2);
      spr.print("Record fail!");
      lcd_PushColors(0, 0, WIDTH, 100, (uint16_t *)spr.getPointer());
    }
  }

  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("Wifi reconnect");
    WiFi.reconnect();
    while (WiFi.status() != WL_CONNECTED)
    {
      delay(100);
    }
  }

#endif
}
